import * as Cesium from 'cesium';
import GaussianSplatPipelineStage from './GaussianSplatPipelineStage';
import GaussianSplatTexturePipelineStage from './GaussianSplatTexturePipelineStage';
export default function fixModelRuntimePrimitive() {
    //@ts-ignore
    Cesium.ModelRuntimePrimitive.prototype.configurePipeline = function (frameState: Cesium.FrameState) {
        const pipelineStages = this.pipelineStages;
        pipelineStages.length = 0;

        const primitive = this.primitive;
        const node = this.node;
        const model = this.model;

        const customShader = model.customShader;
        const style = model.style;
        //@ts-ignore
        const useWebgl2 = frameState.context.webgl2;
        const mode = frameState.mode;
        const use2D =
            mode !== Cesium.SceneMode.SCENE3D && !frameState.scene3DOnly && model._projectTo2D;
        const hasVerticalExaggeration =
            //@ts-ignore
            frameState.verticalExaggeration !== 1.0 && model.hasVerticalExaggeration;

        const hasMorphTargets =
            Cesium.defined(primitive.morphTargets) && primitive.morphTargets.length > 0;
        const hasSkinning = Cesium.defined(node.skin);
        const hasCustomShader = Cesium.defined(customShader);
        const hasCustomFragmentShader =
            hasCustomShader && Cesium.defined(customShader.fragmentShaderText);
        const materialsEnabled =
            !hasCustomFragmentShader ||
            customShader.mode !== Cesium.CustomShaderMode.REPLACE_MATERIAL;
        //@ts-ignore
        const hasQuantization = Cesium.ModelUtility.hasQuantizedAttributes(
            primitive.attributes,
        );

        const generateWireframeIndices =
            model.debugWireframe &&
            //@ts-ignore
            Cesium.PrimitiveType.isTriangles(primitive.primitiveType) &&
            // Generating index buffers for wireframes is always possible in WebGL2.
            // However, this will only work in WebGL1 if the model was constructed with
            // enableDebugWireframe set to true.
            (model._enableDebugWireframe || useWebgl2);

        const pointCloudShading = model.pointCloudShading;
        const hasAttenuation =
            Cesium.defined(pointCloudShading) && pointCloudShading.attenuation;
        const hasPointCloudBackFaceCulling =
            Cesium.defined(pointCloudShading) && pointCloudShading.backFaceCulling;
        const hasPointCloudStyle =
            primitive.primitiveType === Cesium.PrimitiveType.POINTS &&
            (Cesium.defined(style) || hasAttenuation || hasPointCloudBackFaceCulling);

        const hasOutlines =
            model._enableShowOutline && Cesium.defined(primitive.outlineCoordinates);

        const featureIdFlags = inspectFeatureIds(model, node, primitive);

        const hasClassification = Cesium.defined(model.classificationType);

        const hasGaussianSplats =
            (model?.style?.showGaussianSplatting ?? model.showGaussianSplatting) &&
            (primitive?.isGaussianSplatPrimitive ?? false);
        // Start of pipeline -----------------------------------------------------
        if (use2D) {
            //@ts-ignore
            pipelineStages.push(Cesium.SceneMode2DPipelineStage);
        }
        //@ts-ignore
        pipelineStages.push(Cesium.GeometryPipelineStage);

        if (generateWireframeIndices) {
            //@ts-ignore
            pipelineStages.push(Cesium.WireframePipelineStage);
        }

        if (hasClassification) {
            //@ts-ignore
            pipelineStages.push(Cesium.ClassificationPipelineStage);
        }

        if (hasMorphTargets) {
            //@ts-ignore
            pipelineStages.push(Cesium.MorphTargetsPipelineStage);
        }

        if (hasSkinning) {
            //@ts-ignore
            pipelineStages.push(Cesium.SkinningPipelineStage);
        }

        if (hasPointCloudStyle) {
            //@ts-ignore
            pipelineStages.push(Cesium.PointCloudStylingPipelineStage);
        }

        if (hasQuantization) {
            //@ts-ignore
            pipelineStages.push(Cesium.DequantizationPipelineStage);
        }

        if (materialsEnabled) {
            //@ts-ignore
            pipelineStages.push(Cesium.MaterialPipelineStage);
        }

        // These stages are always run to ensure structs
        // are declared to avoid compilation errors.
        //@ts-ignore
        pipelineStages.push(Cesium.FeatureIdPipelineStage);
        //@ts-ignore
        pipelineStages.push(Cesium.MetadataPipelineStage);
        //@ts-ignore
        pipelineStages.push(Cesium.MetadataPickingPipelineStage);

        if (featureIdFlags.hasPropertyTable) {
            //@ts-ignore
            pipelineStages.push(Cesium.SelectedFeatureIdPipelineStage);
            //@ts-ignore
            pipelineStages.push(Cesium.BatchTexturePipelineStage);
            //@ts-ignore
            pipelineStages.push(Cesium.CPUStylingPipelineStage);
        }

        if (hasVerticalExaggeration) {
            //@ts-ignore
            pipelineStages.push(Cesium.VerticalExaggerationPipelineStage);
        }

        if (hasCustomShader) {
            //@ts-ignore
            pipelineStages.push(Cesium.CustomShaderPipelineStage);
        }
        //@ts-ignore
        pipelineStages.push(Cesium.LightingPipelineStage);

        if (model.allowPicking) {
            //@ts-ignore
            pipelineStages.push(Cesium.PickingPipelineStage);
        }

        if (hasOutlines) {
            //@ts-ignore
            pipelineStages.push(Cesium.PrimitiveOutlinePipelineStage);
        }
        //@ts-ignore
        pipelineStages.push(Cesium.AlphaPipelineStage);
        //@ts-ignore
        pipelineStages.push(Cesium.PrimitiveStatisticsPipelineStage);

        if (hasGaussianSplats) {
            if (!Cesium.defined(primitive.needsGaussianSplatTexture)) {
                pipelineStages.push(GaussianSplatPipelineStage);
            } else if (
                primitive.needsGaussianSplatTexture === false &&
                (primitive?.hasGaussianSplatTexture ?? false)
            ) {
                pipelineStages.push(GaussianSplatTexturePipelineStage);
            }
        }

        return;
    };
}
//#region 无改动原始代码
function inspectFeatureIds(model: any, node: any, primitive: any) {
    let featureIds;
    // Check instances first, as this is the most specific type of
    // feature ID
    if (Cesium.defined(node.instances)) {
        //@ts-ignore
        featureIds = Cesium.ModelUtility.getFeatureIdsByLabel(
            node.instances.featureIds,
            model.instanceFeatureIdLabel,
        );

        if (Cesium.defined(featureIds)) {
            return {
                hasFeatureIds: true,
                hasPropertyTable: Cesium.defined(featureIds.propertyTableId),
            };
        }
    }
    //@ts-ignore
    featureIds = Cesium.ModelUtility.getFeatureIdsByLabel(
        primitive.featureIds,
        model.featureIdLabel,
    );
    if (Cesium.defined(featureIds)) {
        return {
            hasFeatureIds: true,
            hasPropertyTable: Cesium.defined(featureIds.propertyTableId),
        };
    }

    return {
        hasFeatureIds: false,
        hasPropertyTable: false,
    };
}
//#endregion